﻿using System;
using UnityEngine;
using UnityEngine.UI;

public static class SandBoxUtils
{
    public static Vector2 ScreenPointToLocalPointInRectangle(Camera camera, RectTransform rect, Vector2 screenPos)
    {
        RectTransformUtility.ScreenPointToLocalPointInRectangle(rect, screenPos, Camera.current, out var pos);
        return pos;
    }

    public static void UpdateArrow(Vector3 pos, Transform arrow, Transform ArrowRoot)
    {
        int zone;
        const int gap = 50;
        var TargetPos = WorldCameraManager.mainCamera.WorldToViewportPoint(pos);

        if (TargetPos.x < 0 || TargetPos.x > 1 || TargetPos.y < 0 || TargetPos.y > 1)
        {
            zone = 1;
        }
        else
        {
            zone = 0;
        }

        zone = 1;
        if (zone == 1)
        {
            ArrowRoot.gameObject.SetActive(true);
            TargetPos = WorldCameraManager.mainCamera.WorldToScreenPoint(pos);
            var sign = Mathf.Sign(TargetPos.z);
            TargetPos *= sign;
            // Debug.Log(TargetPos);
            TargetPos.x = Mathf.Clamp(TargetPos.x, gap, Screen.width - gap);
            TargetPos.y = Mathf.Clamp(TargetPos.y, gap, Screen.height - gap);
            ArrowRoot.localPosition = new Vector3(TargetPos.x, TargetPos.y, 0f);
        }
        else
        {
            ArrowRoot.gameObject.SetActive(false);
        }

        // Debug.Log($"zone:{zone}");
        if (ArrowRoot.gameObject.activeInHierarchy)
        {
            Vector3 screenPoint = WorldCameraManager.mainCamera.WorldToScreenPoint(pos);
            var sign = Mathf.Sign(screenPoint.z);
            screenPoint *= sign;
            // arrow.LookAt2D(pos);
            arrow.LookAt2D(screenPoint);
        }
    }

    private static float gap = 50;
    private static float last = 50;
    private static Vector3 lastPos;
    private static bool check;
    public static void UpdateArrow(Vector3 pos, Transform arrow, Transform ArrowRoot,bool back)
    {
        int zone;
        // const int gap = 50;
        var TargetPos = WorldCameraManager.mainCamera.WorldToViewportPoint(pos);
        float len = Vector3.Distance(lastPos, TargetPos);
        if (len>0.1f)
        {
            check = true;
            lastPos = TargetPos;
        }
        if (check)
        {
            if (back)
            {
                last++;
            }
            else
            {
                last--;
                last = Math.Max(50, last);
                check = false;
            }
            gap = last;
        }
        if (TargetPos.x < 0 || TargetPos.x > 1 || TargetPos.y < 0 || TargetPos.y > 1)
        {
            zone = 1;
        }
        else
        {
            zone = 0;
        }

        // zone = 1;
        if (zone == 1)
        {
            arrow.gameObject.SetActive(true);
            TargetPos = WorldCameraManager.mainCamera.WorldToScreenPoint(pos);
            var sign = Mathf.Sign(TargetPos.z);
            TargetPos *= sign;
            // Debug.Log(TargetPos);
            var old = new Vector3(TargetPos.x, TargetPos.y, TargetPos.z);
            TargetPos.x = Mathf.Clamp(TargetPos.x, gap, Screen.width - gap);
            TargetPos.y = Mathf.Clamp(TargetPos.y, gap, Screen.height - gap);
            ArrowRoot.localPosition = new Vector3(TargetPos.x, TargetPos.y, 0f);
            // LookAt2D(old, arrow);
        }
        else
        {
            arrow.gameObject.SetActive(false);
        }

        // Debug.Log($"zone:{zone}");
        // if (ArrowRoot.gameObject.activeInHierarchy)
        // {
        //     Vector3 screenPoint = WorldCameraManager.mainCamera.WorldToScreenPoint(pos);
        //     var sign = Mathf.Sign(screenPoint.z);
        //     screenPoint *= sign;
        //     // arrow.LookAt2D(pos);
        //     arrow.LookAt2D(screenPoint);
        // }
    }
    
    private static void LookAt2D(Vector3 target,Transform arrow)
    {
        Vector3 dir = target - WorldCameraManager.mainCamera.WorldToScreenPoint(arrow.position);
        var sign = Mathf.Sign(dir.z);
        // print(dir);
        dir *= sign;
        // Debug.DrawLine(arrow.position,target,Color.red);
        // Debug.DrawLine(target,dir,Color.blue);
        // Debug.DrawLine(dir,arrow.position,Color.magenta);
        float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
        angle -= 90;
        // var rot = Quaternion.AngleAxis(angle, Vector3.forward);
        arrow.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
        var localAngles = arrow.localEulerAngles;
        localAngles.x = 0;
        arrow.localEulerAngles = localAngles;
    }

    private static Vector3 LookAt2D(Vector3 self, Vector3 target, float offset = 0)
    {
        Vector3 direction = target - self;
        float angle = Mathf.Atan2(direction.z, direction.x) * Mathf.Rad2Deg + offset;
        return Quaternion.AngleAxis(angle, Vector3.forward).eulerAngles;
    }

    public static void LookAt2D(this Transform tr, Transform target)
    {
        Vector3 relative = tr.InverseTransformPoint(target.position);
        float angle = Mathf.Atan2(relative.x, relative.y) * Mathf.Rad2Deg;
        tr.Rotate(0, 0, -angle, Space.Self);
    }

    public static void LookAt2D(this Transform tr, Vector3 pos)
    {
        Vector3 relative = tr.InverseTransformPoint(pos);
        float angle = Mathf.Atan2(relative.x, relative.y) * Mathf.Rad2Deg;
        // angle -= 90;
        tr.Rotate(0, 0, -angle, Space.Self);
    }

    // public static void LookAt2D(this Transform from, Vector3 to)
    // {
    //     float dx = to.x - from.transform.position.x;
    //     float dy = to.y - from.transform.position.y;
    //     float rotationZ = Mathf.Atan2(dy, dx) * 180 / Mathf.PI;
    //     rotationZ -= 90;
    //
    //     float originRotationZ = from.eulerAngles.z;
    //     float addRotationZ = rotationZ - originRotationZ;
    //     if (addRotationZ > 180)        
    //         addRotationZ -= 360;
    //     from.eulerAngles = new Vector3(0, 0, from.eulerAngles.z + addRotationZ);
    // }
    
    private static Camera _UICamera;
    public static Camera UICamera
    {
        get
        {
            if (_UICamera == null)
            {
                var go = GameObject.Find("UIRoot");
                _UICamera = go.GetComponent<Camera>();
            }

            return _UICamera;
        }
    }
    
    public static Vector3 WorldToUI(Camera camera,Vector3 pos){
        CanvasScaler scaler = GameObject.Find("UIRoot").GetComponent<CanvasScaler>();
 
        float resolutionX = scaler.referenceResolution.x;
        float resolutionY = scaler.referenceResolution.y;
 
        Vector3 viewportPos = camera.WorldToViewportPoint(pos);
 
        Vector3 uiPos = new Vector3(viewportPos.x * resolutionX ,
            viewportPos.y * resolutionY ,0);
 
        return uiPos;
    }
    
    public static Vector2 WorldToUIPoint(Canvas canvas,Vector3 worldPos)
    {
        Vector2 pos;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform,
            WorldCameraManager.mainCamera.WorldToScreenPoint(worldPos), canvas.worldCamera, out pos);
        // RectTransform rect = canvas.transform as RectTransform;
        return pos;
    }

}